#include "OverImgTask.h"
OverImgTask::OverImgTask(char* body, int client_fd, int len, int shmid, int msgid) :BaseTask(body, client_fd, len, shmid, msgid)
{

}

void OverImgTask::working()
{

	OVERIMG_REQ req = { 0 };
	memcpy(&req, body, sizeof(OVERIMG_REQ));
	char name[100];
	sprintf(name, "%d%s", req.user_id, req.img_name);

	cout << "------------------------文件操作日志------------------" << endl;
	// 获取当前时间点（系统时钟）
	auto now = std::chrono::system_clock::now();
	auto in_time_t = std::chrono::system_clock::to_time_t(now);
	std::stringstream ss;
	ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S");
	cout << "时间: " << ss.str() <<"\n" 
	<< "功能：文件保存\n"
	<< "类型：接收\n" 
	<< "用户id：" << req.user_id << "\n"
	<< "接收数据包：" << "\n"
	<< "文件名:" << req.img_name << endl;

	//写入文件
	LogManager& log_fd = LogManager::getInstance();
	ofstream& fd = log_fd.getLogStream();
	fd << "时间: " << ss.str() << "\n"
		<< "功能：文件保存\n"
		<< "类型：接收\n"
		<< "用户id：" << req.user_id << "\n"
		<< "接收数据包：" << "\n"
		<< "文件名:" << req.img_name << "\n"
	<< "--------------------------------------------" << "\n\n";
	// 4. 强制刷新缓冲区（确保日志立即写入文件）
	fd.flush();
	int size = img_data[name][1].nums; //碎片总数
	string namepath(req.img_name);
	cout << "碎片总数 " << size << endl;
	cout << "容器内的数量 " << img_data[name].size() << endl;
	if (img_data[name].size() == size) //判断发送过来的碎片数是否缺失
	{			
		// 打开输出文件
		std::ofstream out_file("data/"+namepath, std::ios::binary);
		for(int i=1;i<=size;i++)//遍历写入文件保存
		{
			out_file.write(img_data[name][i].imgdata,img_data[name][i].length);
		}
		//关闭文件
		out_file.close();
		//响应体
		SAVEIMG_RESP resp = { 0 };
		Img  img;
		img.img_type = 0;
		strcpy(img.img_name, req.img_name);
		strcpy(img.img_path, img_data[name][1].img_path);
		resp.lost_nums = 0;
		strcpy(resp.lost_name, req.img_name);
		string path = "data/" + namepath;
		strcpy(resp.lost_name, req.img_name);
		strcpy(resp.message, "特征图片：保存文件成功！！！\n");
		model->insetImg(img, req.user_id, path);
		resp.status_code = Success;
		cout << "返回图片路径" << resp.lost_name << endl;
		send(resp, req.user_id);
		//清掉这个缓存
		img_data.erase(name);
	}
	else 
	{
		SAVEIMG_RESP resp = { 0 };
		resp.lost_nums = 0; // 缺失总数
		strncpy(resp.message, "特征图片：文件不完整", sizeof(resp.message) - 1);
		resp.status_code = Failure;
		strncpy(resp.lost_name, req.img_name, sizeof(resp.lost_name) - 1);

		cout << "检查图片分片完整性: " << resp.lost_name << endl;

		// 安全遍历寻找缺失分片
		for (int i = 1; i <= size; i++)
		{
			if (img_data[name].find(i)== img_data[name].end())
			{
				// 记录缺失分片序号
				resp.lost_arr[resp.lost_nums] = i;
				cout << "发现缺失分片: " << i << endl;
				resp.lost_nums++;
			}
		}

		cout << "总缺失分片数: " << resp.lost_nums << endl;

		// 发送响应
		send(resp, req.user_id);

	}
}

void OverImgTask::send(SAVEIMG_RESP &resp,int &user_id)
{
	char send[MEMORYSIZE] = { 0 };
	HEAD head = { 0 };
	//写头
	head.checksum = 10;
	head.data_len = sizeof(SAVEIMG_RESP);
	head.index = 1;
	head.service_type = OVERIMG;
	//头体结合
	memcpy(send, &head, sizeof(HEAD));
	memcpy(send + sizeof(HEAD), &resp, sizeof(SAVEIMG_RESP));
	//寻找空闲数据快
	ShmControl* shm = (ShmControl*)shmat(shmid, NULL, 0);
	int index = -1;//空闲下标
	// 寻找下一个空闲块（状态0）
	for (int i = 0; i < MEMORYNUMBER; i++) {
		int status = shm->blocks[i].status;
		if (status == 0) { // 空闲
			index = i;
			break;
		}
	}	
	//写入共享内存
	sem_p(sem_shm, 0);//获取共享内存锁
	ShmBlock* block = &shm->blocks[index];
	memcpy(block->data, send, sizeof(block->data));//考入共享内存
	block->status = 1;                   // 标记为已写
	shmdt(shm);
	sem_v(sem_shm, 0);//释放共享内存锁

	//写入消息队列
	MSG msg = { 0 };
	msg.client_fd = client_fd;
	msg.index = index;
	msg.mtype = 1;
	msgsnd(msgid, &msg, sizeof(MSG), 0);

	cout << "------------------------文件操作日志------------------" << endl;
	// 获取当前时间点（系统时钟）
	auto now = std::chrono::system_clock::now();
	auto in_time_t = std::chrono::system_clock::to_time_t(now);
	std::stringstream ss;
	ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S");
	cout << "时间: "<<ss.str()<<"\n"  // ctime自带换行
	 << "功能：文件保存\n"
	<< "类型：发送\n"
	<< "用户id：" <<user_id<< "\n"
	<< "发送数据包：\n" 
	<<"状态："<<resp.status_code<<"\n"
	<<resp.message<<"\n"
	<< "文件名:" << resp.lost_name << endl;

	//写入文件
	LogManager& log_fd = LogManager::getInstance();
	ofstream& fd = log_fd.getLogStream();
	fd << "时间: " << ss.str() << "\n"  // ctime自带换行
		<< "功能：文件保存\n"
		<< "类型：发送\n"
		<< "用户id：" << user_id << "\n"
		<< "发送数据包：\n"
		<< "状态：" << resp.status_code << "\n"
		<<  resp.message << "\n"
		<< "文件名:" << resp.lost_name << "\n"
		<< "--------------------------------------------" << "\n\n";

	// 4. 强制刷新缓冲区（确保日志立即写入文件）
	fd.flush();
}
